/*
 * @author Chris
 * @since 2023/2/2 19:25
 *
 * @brief    The project will ...
 *
 * @note     ...
 *
 * @warning  Do not to ...
 *
 * Change Logs:
 *   Date           Author       Notes
 *   2023/2/2     Chris        the first version
 */
#include "8052.h"

#define _nop_() __asm nop __endasm
#define I2CDelay() _nop_();_nop_();_nop_();_nop_();

#define I2C_SDA P3_6
#define I2C_SCL P3_7

void I2CStart() {
    I2C_SCL = 1;
    I2C_SDA = 1;
    I2C_SDA = 0;
    I2CDelay();
    I2C_SCL = 0;
}

__sbit I2CWrite(unsigned char dat) {
    I2C_SCL = 0;        // 拉低 SCL，以便主机修改数据

    // 发送数据
    for (unsigned char mask = 0x80; mask != 0; mask >>= 1) {
        I2C_SDA = (mask & dat) == 0 ? 0 : 1;
        I2C_SCL = 1;    // 拉高 SCL，让从机读取数据
        I2CDelay();
        I2C_SCL = 0;    // 拉低 SCL，以便后续主机继续发送数据
    }

    // 数据发送完成，读取从机的应答位
    I2C_SDA = 1;        // 拉高 SDA，防止主机干扰应答位读取
    I2C_SCL = 1;        // 拉高 SCL，以便读取从机应答值
    I2CDelay();
    __sbit ack = I2C_SDA;
    I2C_SCL = 0;        // 拉低 SCL，以便主机继续发送数据

    return ~ack;
}

void I2CStop() {
    I2C_SCL = 0;
    I2C_SDA = 0;
    I2C_SCL = 1;
    I2CDelay();
    I2C_SDA = 1;
}

unsigned char I2CRead(__sbit ack) {
    I2C_SDA = 1;        // 确保主机释放数据总线，不干扰读取结果

    // 读取数据
    unsigned char dat;
    for (unsigned char mask = 0x80; mask != 0; mask >>= 1) {
        I2C_SCL = 1;    // 拉高 SCL，读取从机数据
        dat = I2C_SDA == 0 ? (dat & (~mask)) : (dat | mask);
        I2C_SCL = 0;    // 拉低 SCL，以便从机修改 SDA 继续发送数据
        I2CDelay();
    }

    // 数据读取完成，回复应答位，确定是否继续读取
    I2C_SCL = 0;        // 拉低 SCL，以便主机发送应答位
    I2C_SDA = ack;      // 数据读取完成，回应应答位：0，继续读取；1，不再读取
    I2C_SCL = 1;        // 拉高 SCL，以便从机读取应答位
    I2CDelay();
    I2C_SCL = 0;
    return dat;
}

unsigned char I2CReadAck() {
    I2CRead(0);
}

unsigned char I2CReadNack() {
    I2CRead(1);
}
